package com.lg.cms.utils;

import cn.hutool.core.io.FileUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.google.gson.Gson;
import com.lg.cms.dto.ALiYunConfigDTO;
import com.lg.cms.dto.QiNiuYunConfigDTO;
import com.lg.cms.entity.SaveConfig;
import com.lg.cms.service.SaveConfigService;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.Json;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @Description: 上传文件工具类
 * @INFO: 此工具类上传不提供文件后缀的验证, 只提供文件非空验证
 * @Author: wuyuhang
 * @create: 2020-09-24 12:41
 */

@Component
public class UploadFileUtil {

    /**
     * 导入上传配置service
     */
    @Autowired
    SaveConfigService saveConfigService;

    /**
     * 导入redis工具类
     */
    @Resource
    RedisUtil redisUtil;

    /**
     * 获取本地文件上传根目录和uri映射
     */
    @Value("${file.path}")
    String baseDir;
    @Value("${file.uri}")
    String baseUri;

    /**
     * 上传文件管理员设置(七牛, 阿里, 本地, 自动选择)
     *
     * @param file
     * @return R
     * 上传成功:
     *      R.code(long): 0
     *      R.msg(String): 执行成功!
     *      R.data(String): 访问url
     * 上传失败:
     *      R.code(long): -1
     *      R.msg(String): 具体错误消息
     */
    public R<String> uploadAuto(MultipartFile file){
        System.out.println("进入uploadAuto");
        SaveConfig saveConfig = saveConfigService.getOne(new QueryWrapper<SaveConfig>().eq("`use`", true));
        System.out.println(saveConfig);
        if(saveConfig == null){
            System.out.println("saveconfig null");
            return this.uploadLocal(file);
        }else {
            if (saveConfig.getKey().equals("qiniuyun")) {
                System.out.println("上传七牛");
                return this.uploadQiNiuYun(file);
            } else if (saveConfig.getKey().equals("aliyun")) {
                System.out.println("上传阿里");
                return this.uploadALiYun(file);
            }else{
                System.out.println("上传本地");
                return this.uploadLocal(file);
            }
        }
    }

    /**
     * 上传文件到七牛云
     *
     * @param file
     * @return R
     * 上传成功:
     *      R.code(long): 0
     *      R.msg(String): 执行成功!
     *      R.data(String): 访问url
     * 上传失败:
     *      R.code(long): -1
     *      R.msg(String): 具体错误消息
     */
    public R<String> uploadQiNiuYun(MultipartFile file) {
        if (file == null) {
            return R.failed("文件为空");
        }
        //加载七牛云配置信息
        QiNiuYunConfigDTO yun = loadQiNiuYunConfig();
        //创建不指定地区的空配置
        Configuration cfg = new Configuration();
        //创建上传器
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(yun.getAccessKey(), yun.getSecretKey());
        String upToken = auth.uploadToken(yun.getBucketName());
        String key = "";
        if (yun.getPrefix() != null) {
            key += yun.getPrefix();
        }
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        key += System.currentTimeMillis() + suffix;
//        System.out.println("七牛云key: " + key);
        try {
            byte[] fileBytes = file.getBytes();
            ByteArrayInputStream byteInputStream = new ByteArrayInputStream(fileBytes);
            try {
                Response response = uploadManager.put(byteInputStream, key, upToken, null, null);
                //解析上传成功的结果
                DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
//                System.out.println("putRet: " + putRet);
//                System.out.println("putRet-key: " + putRet.key);
//                System.out.println("putRet-hash: " + putRet.hash);
                return R.ok("http://" + yun.getDomain() + "/" + putRet.key);
            } catch (QiniuException ex) {
                Response r = ex.response;
//                System.err.println(r.toString());
//                System.out.println("上传时出错");
                return R.failed(r.toString());
//                try {
//                    System.err.println(r.bodyString());
//                } catch (QiniuException ex2) {
//                    //ignore
//                }
            }

        } catch (IOException ioException) {
            return R.failed("文件转字节流时出错");
        } catch (IllegalArgumentException illegalArgumentException) {
            return R.failed("七牛云配置信息出错， 无法连接到七牛云， 请修改您的配置");
        } catch (Exception e) {
            return R.failed("未知错误");
        }

    }

    /**
     * 上传文件到阿里云
     *
     * @param file
     * @return R
     * 上传成功:
     *      R.code(long): 0
     *      R.msg(String): 执行成功!
     *      R.data(String): 访问url
     * 上传失败:
     *      R.code(long): -1
     *      R.msg(String): 具体错误消息
     */
    public R<String> uploadALiYun(MultipartFile file) {
        if (file == null) {
            return R.failed("文件为空");
        }
        //加载阿里云配置
        ALiYunConfigDTO yun = loadALiYunConfig();
        String bucketName = yun.getBucketName();
        String endPoint = yun.getEndPoint();
        String accessKeyId = yun.getAccessKeyId();
        String accessKeySecret = yun.getAccessKeySecret();
        String path = "http://";
        path += yun.getDomain();
        String fileName = "";
        if (yun.getPrefix() != null) {
            fileName += yun.getPrefix();
        }
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        fileName += System.currentTimeMillis() + suffix;
        path += "/" + fileName;
//        System.out.println("阿里云key: " + fileName);
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
        try {
            byte[] fileBytes = file.getBytes();
            ossClient.putObject(bucketName, fileName, new ByteArrayInputStream(fileBytes));
//            System.out.println("http://" + yun.getDomain() + "/" + fileName);
            return R.ok(path);
        } catch (IOException ioException) {
            return R.failed("文件转字节流时出错");
        } catch (ClientException ce) {
            return R.failed(ce.getMessage());
        } catch (OSSException oe) {
            return R.failed(oe.getMessage());
        }


    }

    /**
     * 上传文件到本地
     *
     * @param file
     * @return R
     * 上传成功:
     *      R.code(long): 0
     *      R.msg(String): 执行成功!
     *      R.data(String): 访问url
     * 上传失败:
     *      R.code(long): -1
     *      R.msg(String): 具体错误消息
     */
    public R<String> uploadLocal(MultipartFile file) {
        System.out.println("进入上传本地");
        if (file == null) {
            return R.failed("文件为空");
        }
//        System.out.println("baseDir: " + baseDir);
//        System.out.println("baseUri: " + baseUri);
        //获取base dir,截取掉`file:`前缀
        String myBaseDir = baseDir.substring(5);
        String myBaseUri = baseUri.substring(0, baseUri.lastIndexOf("/"));
//        System.out.println("myBaseDir: " + myBaseDir);
//        System.out.println("myBaseUri: " + myBaseUri);
        //获取当前年月日
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String currentDatePath = myBaseDir + "/" + sdf.format(date);
        String uri = myBaseUri + "/" + sdf.format(date);
//        System.out.println("今日目录: " + currentDatePath);
        //判断目录是否存在, 不存在创建
        if (!FileUtil.exist(currentDatePath)) {
            FileUtil.mkdir(currentDatePath + "/1");
        }
        File[] files = FileUtil.ls(currentDatePath);
        //获取当前文件下所有文件夹
        Integer fileMaxIndex = 0;
        for (File file1 : files) {
            if (file1.isDirectory()) {
                Integer temp = Integer.valueOf(file1.getName());
                if (temp > 0) {
                    fileMaxIndex = temp;
                }
            }
        }
        //获取索引最大的文件
        File lastFile = new File(currentDatePath + "/" + fileMaxIndex.toString());

        //判断当前文件下有多少个文件, 超过1000个创建一个新的文件夹
        if (FileUtil.listFileNames(lastFile.toString()).size() > 1000) {
            FileUtil.mkdir(currentDatePath + "/" + String.valueOf(fileMaxIndex + 1));
            lastFile = new File(currentDatePath + "/" + String.valueOf(fileMaxIndex + 1));

        }
//        System.out.println("本文件上传目录: " + lastFile.getAbsolutePath());
        uri += "/" + lastFile.getName();
        String fileNameSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String fileName = String.valueOf(System.currentTimeMillis()) + fileNameSuffix;
        File tempFile = new File(lastFile.getAbsolutePath() + "/" + fileName);
        uri += "/" + fileName;
//        System.out.println("最终uri: " + uri);
//        System.out.println("最终存储目录: " + tempFile.getAbsolutePath());
        try {
            file.transferTo(tempFile);
            return R.ok(uri);
        } catch (Exception ignored) {
            return R.failed("上传文件时出错");
        }
    }

    /**
     * 测试七牛云配置连通性
     *
     * @return R
     * 测试通过:
     *      R.code(long): 0
     *      R.msg(String): 执行成功!
     *      R.data(String): "测试七牛云连通成功"
     * 上传失败:
     *      R.code(long): -1
     *      R.msg(String): 具体错误消息
     */
    public R<String> testQiNiuYun() {
        QiNiuYunConfigDTO yun = loadQiNiuYunConfig();
        //创建不指定地区的空配置
        Configuration cfg = new Configuration();
        //创建上传器
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(yun.getAccessKey(), yun.getSecretKey());
        String upToken = auth.uploadToken(yun.getBucketName());
        try {
            Response response = uploadManager.put(String.valueOf(System.currentTimeMillis()).getBytes(), null, upToken);
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            return R.ok("测试七牛云连通成功");
        } catch (IllegalArgumentException illegalArgumentException) {
            return R.failed("测试七牛云连通失败: 七牛云配置信息出错， 无法连接到七牛云， 请修改您的配置");
        } catch (QiniuException ex) {
            Response r = ex.response;
            return R.failed("测试七牛云连通失败: " + r.toString());
        } catch (Exception e) {
            return R.failed("测试七牛云连通失败: 未知错误");
        }
    }

    /**
     * 测试阿里云配置连通性
     *
     * @return R
     * 测试通过:
     *      R.code(long): 0
     *      R.msg(String): 执行成功!
     *      R.data(String): "测试阿里云连通成功"
     * 上传失败:
     *      R.code(long): -1
     *      R.msg(String): 具体错误消息
     */
    public R<String> testALiYun() {
        ALiYunConfigDTO yun = loadALiYunConfig();
        String bucketName = yun.getBucketName();
        String endPoint = yun.getEndPoint();
        String accessKeyId = yun.getAccessKeyId();
        String accessKeySecret = yun.getAccessKeySecret();
        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
        try {
            ossClient.putObject(bucketName, String.valueOf(System.currentTimeMillis()),
                    new ByteArrayInputStream(String.valueOf(System.currentTimeMillis()).getBytes()));
            return R.ok("测试阿里云连通成功");
        } catch (ClientException ce) {
            return R.failed("测试阿里云连通失败:" + ce.getMessage());
        } catch (OSSException os) {
            return R.failed("测试阿里云连通失败:" + os.getMessage());
        }
    }

    /**
     * 获取七牛云DTO配置信息
     *
     * @return 七牛云配置dto对象
     */
    private QiNiuYunConfigDTO loadQiNiuYunConfig() {
        return Json.decode(
                saveConfigService.getOne(new QueryWrapper<SaveConfig>().eq("`key`", "qiniuyun")).getValue()
                , QiNiuYunConfigDTO.class);
    }

    /**
     * 获取阿里云DTO配置信息
     *
     * @return 阿里云配置dto对象
     */
    private ALiYunConfigDTO loadALiYunConfig() {
        return Json.decode(
                saveConfigService.getOne(new QueryWrapper<SaveConfig>().eq("`key`", "aliyun")).getValue()
                , ALiYunConfigDTO.class);
    }
}